package gu.simplemq.jms;

import java.net.URI;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentMap;

import javax.jms.Connection;

import com.google.common.collect.Maps;

import gu.simplemq.Constant;

import static com.google.common.base.Preconditions.checkNotNull;


/**
 * 延迟初始化的 {@link Connection}资源池（线程安全）,使用方法:<br>
 * 通过 {@link #getDefaultInstance()} 和getInstance(...)系列静态方法获取{@link JmsPoolLazy}实例<br>
 * 通过{@link #apply()} 和 {@link #free()}方法实现{@link Connection}对象的申请和释放
 * @author guyadong
 *
 */
public class JmsPoolLazys implements Constant{
	final JmsRuntimeContext runtimeContext;
	/** {@link JmsPoolLazy }实例集合 */
	final ConcurrentMap<URI,JmsPoolLazy> POOLS = Maps.newConcurrentMap();
	/** 默认连接池实例 */
	private volatile JmsPoolLazy defaultInstance;
	
	public JmsPoolLazys(JmsRuntimeContext runtimeContext) {
		this.runtimeContext = runtimeContext;
	}

	/**
	 * 返回默认实例,如果 {@link #defaultInstance}为null则创建默认实例
	 * @return
	 * @see #createDefaultInstance(Map)
	 */
	public JmsPoolLazy getDefaultInstance() {
		return null == defaultInstance
				? createDefaultInstance(null) 
				: defaultInstance;
	}

	/**
	 * 设置默认{@link JmsPoolLazy}实例<br>
	 * 仅当默认实例未初始化(为{@code null})且输入参数不为{@code null}时有效(返回{@code true})
	 * 如果默认实例已经初始化,则输出警告日志,返回{@code false}
	 * @param poolLazy 为{@code null}返回{@code false}
	 * @return  设置成功返回{@code true},否则返回{@code false}
	 */
	public boolean setDefaultInstance(JmsPoolLazy poolLazy) {
		// double checking
		if(null == defaultInstance){
			synchronized(JmsPoolLazys.class){
				if(null == defaultInstance && null != poolLazy){
					defaultInstance = poolLazy;
					return true;
				}
			}
		}
		logger.warn("INVALID INVOCATION,default instance was initialized already before this invocation");
		return false;
	}

	/**
	 * 检测默认实例是否初始化
	 * @return 默认实例已经初始化则返回{@code true},否则返回false
	 */
	public boolean defaultInstanceInitialized(){
		return defaultInstance != null;
	}
	/**
	 * 根据指定的连接参数创建默认实例,只能被调用一次(线程安全)
	 * @param props
	 * @return
	 */
	public final JmsPoolLazy createDefaultInstance(Properties props){
		setDefaultInstance( getInstance(props));
		return defaultInstance;
	}
	@SuppressWarnings("rawtypes")
	JmsPoolLazy createInstance(Map props) {
		return new JmsPoolLazy(props, this);
	}
	/**
	 * 查找在连接池对象集合中查找对应的匹配的对象,找不到就创建新实例
	 * @param props
	 * @return
	 */
	public synchronized JmsPoolLazy getInstance(Properties props) {
		// 查找在连接池对象集合中查找对应的匹配的对象,找不到就创建新实例
		URI location =  runtimeContext.getPropertiesHelper().getLocationlURI(props);
		JmsPoolLazy found = POOLS.get(location);
		return found == null ? createInstance(props) : found;
	
	}
	
	/**
	 * 根据uri查找在连接池对象集合中查找对应的匹配的对象,找不到就创建新实例
	 * @param uri
	 * @return
	 */
	public JmsPoolLazy getInstance(URI uri) {
		Properties props = new Properties();
		props.setProperty(MQ_URI, checkNotNull(uri,"uri is null").toString());
		return getInstance(props);
	}
	
	public JmsPoolLazy getInstanceByURI(String uri) {
		 return getInstance(URI.create(uri));
	}
	/**
	 * 关闭并删除所有资源池中的{@link JmsPoolLazy}实例
	 */
	public synchronized void closeAll(){
		for(Iterator<JmsPoolLazy> itor = POOLS.values().iterator();itor.hasNext();){
			JmsPoolLazy p = itor.next();
			itor.remove();
			p.close();
		}
	}
}
